#include <am.h>
#include <klib.h>
#include <klib-macros.h>

#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
static unsigned long int next = 1;

extern char _heap_start;
extern Area heap;
// static void* addr = heap.start;
static void* addr = (void *)(&_heap_start);

int rand(void) {
  // RAND_MAX assumed to be 32767
  next = next * 1103515245 + 12345;
  return (unsigned int)(next/65536) % 32768;
}

void srand(unsigned int seed) {
  next = seed;
}

int abs(int x) {
  return (x < 0 ? -x : x);
}

int atoi(const char* nptr) {
  int x = 0;
  while (*nptr == ' ') { nptr ++; }
  while (*nptr >= '0' && *nptr <= '9') {
    x = x * 10 + *nptr - '0';
    nptr ++;
  }
  return x;
}

char *sitoa(int num, char *str, int radix) {
  if (num == 0) {
    str[0] = '0';
    str[1] = '\0';
    return str;
  }

  char buf[33];

  int ptr_str = 0, ptr_buf = 0;
  switch (radix) {
    case 10: {
      int sign = num >= 0 ? 1: -1;
      if (sign < 0) {
        str[ptr_str++] = '-';
        num = -num;
      }

      while (num != 0) {
        buf[ptr_buf++] = num % 10 + '0';
        num /= 10;
      }
      break;
    }

    case 16: {
      unsigned int num_uns = (unsigned int)num;
      int remainder = 0;
      while (num_uns != 0) {
        remainder = num_uns % 16;
        if (remainder >= 0 && remainder <= 9) {
          buf[ptr_buf++] = remainder + '0';
        } else {
          buf[ptr_buf++] = remainder - 10 + 'a';
        }
        num_uns /= 16;
      }

      break;
    }
  }

  ptr_buf--;
  while (ptr_buf >= 0) {
    str[ptr_str++] = buf[ptr_buf--];
  }
  str[ptr_str] = '\0';

  return str;
}

char *slitoa(long num, char *str, int radix) {
  if (num == 0) {
    str[0] = '0';
    str[1] = '\0';
    return str;
  }

  char buf[65];

  int ptr_str = 0, ptr_buf = 0;
  switch (radix) {
    case 10: {
      int sign = num >= 0 ? 1: -1;
      if (sign < 0) {
        str[ptr_str++] = '-';
        num = -num;
      }

      while (num != 0) {
        buf[ptr_buf++] = num % 10 + '0';
        num /= 10;
      }
      break;
    }

    case 16: {
      unsigned long num_uns = (unsigned long)num;
      long int remainder = 0;
      while (num_uns != 0) {
        remainder = num_uns % 16;
        if (remainder >= 0 && remainder <= 9) {
          buf[ptr_buf++] = remainder + '0';
        } else {
          buf[ptr_buf++] = remainder - 10 + 'a';
        }
        num_uns /= 16;
      }

      break;
    }
  }

  ptr_buf--;
  while (ptr_buf >= 0) {
    str[ptr_str++] = buf[ptr_buf--];
  }
  str[ptr_str] = '\0';

  return str;
}

char *uitoa(unsigned int num, char *str, int radix) {
  if (num == 0) {
    str[0] = '0';
    str[1] = '\0';
    return str;
  }

  char buf[33];

  int ptr_str = 0, ptr_buf = 0;
  switch (radix) {
    case 10: {
      while (num != 0) {
        buf[ptr_buf++] = num % 10 + '0';
        num /= 10;
      }
      break;
    }

    case 16: {
      unsigned int num_uns = (unsigned int)num;
      int remainder = 0;
      while (num_uns != 0) {
        remainder = num_uns % 16;
        if (remainder >= 0 && remainder <= 9) {
          buf[ptr_buf++] = remainder + '0';
        } else {
          buf[ptr_buf++] = remainder - 10 + 'a';
        }
        num_uns /= 16;
      }

      break;
    }
  }

  ptr_buf--;
  while (ptr_buf >= 0) {
    str[ptr_str++] = buf[ptr_buf--];
  }
  str[ptr_str] = '\0';

  return str;
}

void *malloc(size_t size) {
  // On native, malloc() will be called during initializaion of C runtime.
  // Therefore do not call panic() here, else it will yield a dead recursion:
  //   panic() -> putchar() -> (glibc) -> malloc() -> panic()
#if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__))
  // panic("Not implemented");
  void *ret = NULL;
  if ((heap.end - addr) >= size) {
    ret = addr;
    addr = (char *)addr + size;
    return ret;
  }
#endif
  return NULL;
}

void free(void *ptr) {
}

#endif
